 /*
 * copyright (c) 2013 Blaise-Florentin Collin
 *
 * This file is part of astroDCAM.
 *
 * AstroAviBrowser is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License v3
 * as published by the Free Software Foundation
 *
 * AstroAviBrowser is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * v3 along with AstroAviBrowser; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA
 */

///
/// \file frame.cpp
/// \brief Frames definitions
///

// C std includes
#include <malloc.h>

// C++ std includes
#include <cstddef>

// C++ app includes
#include "frame.hpp"

// setting consts
const int frame::MONO=0;
const int frame::BAYER_RGGB=8;
const int frame::BAYER_GRBG=9;
const int frame::BAYER_GBRG=10;
const int frame::BAYER_BGGR=11;
const int frame::BAYER_CYYM=16;
const int frame::BAYER_YCMY=17;
const int frame::BAYER_YMCY=18;
const int frame::BAYER_MYYC=19;
const int frame::RGB=100;
const int frame::BGR=101;

const int frame::NO_ERROR=0;
const int frame::NO_MEM=-1;
const int frame::INVALID_ARGS=-2;

//
// constructors
//

//
// simple constructor
//
frame::frame() {
   width=0;
   height=0;
   color=MONO;
   depth=0;

   mono_plan=NULL;
   red_plan=NULL;
   green_plan=NULL;
   blue_plan=NULL;

   observer="unknown";
   camera="unknown";
   telescope="unknown";
   frameDate=0;
   frameDateUTC=0;
}

//
// full constructor
//
frame::frame(int w,int h,int c,int d, string o="unknown", string cam="unknown", string t="unknown", int64_t date=0, int64_t dateUTC=0) {
   observer=o;
   camera=cam;
   telescope=t;
   frameDate=0;
   frameDateUTC=0;

   if(allocateMem(w,h,c,d)==NO_ERROR) {
      width=w;
      height=h;
      color=c;
      depth=d;
   } else {
      width=0;
      height=0;
      color=MONO;
      depth=0;

      mono_plan=NULL;
      red_plan=NULL;
      green_plan=NULL;
      blue_plan=NULL;
   }
}

//
// copy constructor
//
frame::frame(const frame &f) {
   observer=f.observer;
   camera=f.camera;
   telescope=f.telescope;
   frameDate=f.frameDate;
   frameDateUTC=f.frameDateUTC;

   if(allocateMem(f.width,f.height,f.color,f.depth)==NO_ERROR) {
      width=f.width;
      height=f.height;
      color=f.color;
      depth=f.depth;
   } else {
      width=0;
      height=0;
      color=MONO;
      depth=0;

      mono_plan=NULL;
      red_plan=NULL;
      green_plan=NULL;
      blue_plan=NULL;
   }
}

//
// destructor
//
frame::~frame() {
   releaseMem();
}

//
// copy operator
//
frame& frame::operator=(const frame &f) {
   if(allocateMem(f.width,f.height,f.color,f.depth)==NO_ERROR) {
      width=f.width;
      height=f.height;
      color=f.color;
      depth=f.depth;

      observer=f.observer;
      camera=f.camera;
      telescope=f.telescope;
      frameDate=f.frameDate;
      frameDateUTC=f.frameDateUTC;
   }
}

//
// setters
//

int frame::setWidth(int w) {
   if(w<=0)
      return(INVALID_ARGS);
   if(w==width)
      return(NO_ERROR);
   if(allocateMem(w,height,color,depth)!=NO_ERROR)
      return(NO_MEM);
   width=w;
}

int frame::setHeight(int h) {
   if(h<=0)
      return(INVALID_ARGS);
   if(h==height)
      return(NO_ERROR);
   if(allocateMem(width,h,color,depth)!=NO_ERROR)
      return(NO_MEM);
   height=h;
}

int frame::setColor(int c) {
   if(c < MONO || c > BGR)
      return(INVALID_ARGS);
   if(c==color)
      return(NO_ERROR);
   if(allocateMem(width,height,c,depth)!=NO_ERROR)
      return(NO_MEM);
   color=c;
}

int frame::setDepth(int d) {
   if(d < 1 || d > 2)
      return(INVALID_ARGS);
   if(d==depth)
      return(NO_ERROR);
   if(allocateMem(width,height,color,d)!=NO_ERROR)
      return(NO_MEM);
   depth=d;
}

//
// PRIVATE
//

void frame::releaseMem() {
   if(mono_plan) {
      free(mono_plan);
      mono_plan=NULL;
   }
   if(red_plan) {
      free(red_plan);
      red_plan=NULL;
   }
   if(green_plan) {
      free(green_plan);
      green_plan=NULL;
   }
   if(blue_plan) {
      free(blue_plan);
      blue_plan=NULL;
   }
}


int frame::allocateMem(int w, int h, int c, int d) {
   unsigned char* tmp;
   unsigned char* tmp2;
   unsigned char* tmp3;

   // check parameters
   if(w<=0 || h<=0 || c < MONO || c > BGR || d < 1 || d > 2)
      return(INVALID_ARGS);

   // if mono, just one plan
   if(c < RGB) {
      tmp=(unsigned char*)malloc(w*h*d);
      // malloc failed
      if(tmp==NULL)
         return(NO_MEM);
      mono_plan=tmp;
   // allocate all color plans
   } else {
      // RED
      tmp=(unsigned char*)malloc(w*h*d);
      if(tmp==NULL)
         return(NO_MEM);
      // GREEN
      tmp2=(unsigned char*)malloc(w*h*d);
      if(tmp2==NULL) {
         free(tmp);
         return(NO_MEM);
      }
      // BLUE
      tmp3=(unsigned char*)malloc(w*h*d);
      if(tmp3==NULL) {
         free(tmp);
         free(tmp2);
         return(NO_MEM);
      }

      red_plan=tmp;
      green_plan=tmp2;
      blue_plan=tmp3;
   }
}
